<?php

namespace App\Service;
use Hyperf\DbConnection\Db;
use Hyperf\Utils\ApplicationContext;
class WxPayService
{
//    protected $sp_appid = '';//服务商APPID（目前只有公众号）
//    protected $sp_mchid = '';//服务商商户号

    protected $appid = '';//小程序APPID
    protected $mchid = '';//商户号
    protected $apiV3Key = '';//支付秘钥（服务商V3级别）
    protected $privateKeyPath = '';//证书物理路径（私钥）
    protected $serialNo = '';//证书序列号
    protected $app_secret = '';//小程序通信秘钥
    protected $notify_url = '';//支付回调地址

//    #[Inject]
    public function __construct()
    {
        $container = ApplicationContext::getContainer();
        $this->redis = $container->get(\Hyperf\Redis\Redis::class);
    }
    public function get_applet_id($order_id)
    {
        $res = Db::table('data_payment')->select('applet_id')->where('order_id',$order_id)->first();
        return $res;
    }
    public function get_applet(string $applet_id)
    {
        # 获取小程序基本配置
        $redis_key = "applet:config";
        $applet_info = $this->redis->hGet($redis_key,$applet_id);
        $applet_info = json_decode($applet_info,true);
        if (empty($applet_info)){
            # 获取小程序基本信息
            $applet_info = Db::table("applet")->where([
                "id"=>$applet_id
            ])->first();
            $applet_info = $this->object_to_find_array($applet_info);
            $this->redis->hSet($redis_key,$applet_id,json_encode($applet_info));
        }
        return $applet_info;
    }

    public function unifyPay($buy_info){
        $order_id = $buy_info['order_id'];
        $get_applet_id = $this->get_applet_id($order_id);
        if($get_applet_id) {
            $applet_id = "$get_applet_id->applet_id";
        } else {
            var_dump('获取不到小程序ID');
            return false;
        }
        $applet_info = $this->get_applet($applet_id);
        $this->appid = $applet_info['app_id'];
        $this->app_secret = $applet_info['app_secret'];
        var_dump($applet_info);
//        $this->appid = 'wx72b55e4e61546129';
//        $this->app_secret = '2f81175efc80878fb53562afe65a5dcf';

        $this->mchid = '1658026575';
        $this->apiV3Key = 'R9e223dAp6WQ1zyNt8jgLOFx5hkcMHV7';
        $this->privateKeyPath = '/home/wwwroot/ml_api/wx/10000/apiclient_key.pem';
        $this->serialNo = '504D25AC484AD63DA05EBE9A48F656E3644DE8EA';
        $this->notify_url = 'https://kydj.kuaiyingbox.com/uwx/wechat_bak';
        //这个数组里所有的数据都是必填的
        $unifydata = [
            #应用ID
            'appid' => $this->appid,
            #直连商户号
            'mchid' => $this->mchid,
            #商品描述
            'description' => '充值',
            #订单号
            'out_trade_no' => $buy_info['order_id'],
            #回调地址
            'notify_url' => $this->notify_url,
            #订单金额
            'amount'=>['total'=>intval($buy_info['amount']),'currency'=>'CNY'],
            #支付者
            'payer'=>['openid'=>$buy_info['xc_open_id']],
        ];
        var_dump($unifydata);
        $orderResult = $this->create_pay_order($unifydata);
        var_dump($orderResult);var_dump('2222222222');
        $timeStamp = time();
        $paydata = [
            'appId' => $this->appid,
            'order_id' => $buy_info['order_id'],
            'timeStamp' => "$timeStamp",
            'nonceStr' => md5(rand(100000,999999)),
            'package' => 'prepay_id=' . $orderResult['prepay_id'],
        ];
        $sign = $this->getSign($paydata);//给小程序生成验证签名
        $paydata['signType'] = 'RSA';
        $paydata['paySign'] = $sign;
        unset($paydata['appId']);
        return $paydata;
    }

    public function create_pay_order($inputData){
        $inputData = json_encode($inputData);//v3微信传递参数需要json格式
        $headers = $this->getV3Sign('https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi','POST',$inputData);//将签名放在报头里
        $result = $this -> post_data('https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi',$inputData,$headers);//下单
        return json_decode($result,true);
    }

    public function getV3Sign($url,$http_method,$body) {
        //商户号
        $mchid = $this->mchid;
        //随机字符串
        $nonce = strtoupper($this -> getNoncestr());
        //商户序列号
        $serialNo = $this->serialNo;
        //时间戳
        $timestamp = time();
        //url
        $url_parts = parse_url($url);
        //获取绝对路径
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        //密钥key
        $private_key = $this->getPrivateKey($this->privateKeyPath);
        //拼接参数
        $message = $http_method."\n".
            $canonical_url."\n".
            $timestamp."\n".
            $nonce."\n".
            $body."\n";
        //计算签名值
        openssl_sign($message, $raw_sign, $private_key, 'sha256WithRSAEncryption');
        $sign   = base64_encode($raw_sign);
//        $token  = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',$mchid, $nonce, $timestamp, $serial_no, $sign);
        $token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $mchid, $nonce, $timestamp, $serialNo, $sign);
        $headers = [
            'Accept: application/json',
            'User-Agent: */*',
            'Content-Type: application/json; charset=utf-8',
            'Authorization: '.$token,
        ];
        return $headers;
    }

    public function getNoncestr($length = 32) {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str ="";
        for ( $i = 0; $i < $length; $i++ )  {
            $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
        }
        return $str;
    }

    public function getPrivateKey($filepath) {
        return openssl_get_privatekey(file_get_contents($filepath));
    }

    public function post_data($url,$data=[],$headers=[]){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        //设置header头
        curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);
        // POST数据
        curl_setopt($ch, CURLOPT_POST, 1);
        // 把post的变量加上
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        $output = curl_exec($ch);
        curl_close($ch);
        return $output;
    }

    protected function getSign($data) {
        $tmpstr = $data['appId'] . "\n" . $data['timeStamp'] . "\n" . $data['nonceStr'] . "\n" . $data['package'] . "\n";
        $privateKey         = file_get_contents($this->privateKeyPath);
        $binary_signature   = "";
        $algo               = "SHA256";
        openssl_sign($tmpstr, $binary_signature, $privateKey, $algo);
        $sign               = base64_encode($binary_signature);
        return $sign;
    }

    public function notify(){
//
//        (
//        [id] => 9fb34bc0-64ad-5bcb-8eb7-024c3eaf1608
//        [create_time] => 2023-11-01T16:10:16+08:00
//    [resource_type] => encrypt-resource
//        [event_type] => TRANSACTION.SUCCESS
//        [summary] => 支付成功
//        [resource] => Array
//        (
//            [original_type] => transaction
//            [algorithm] => AEAD_AES_256_GCM
//        [ciphertext] => 7Dn5rOYF7wyZLzF4ey+CO/lWmFM1u0op+MzYaTEy6UZpA9+m/27Fd2kAg8mzWehNYBCpOFeAuGopN4MGm4ZzUxCiyCdwssqEVKgOWbxEbyHwOF/ROJWOKQdw2/X04q3k5pprk9+8DHPXa8xM3UtGULuAI6Az/xunlV2Rp/WMlpRrNLqknik5RpHEchdBDXCsudkckc0bqL2Le+QLk5AAJVbfpQBLuOrQn/PvVWkmvz5AUjM/XMNV0I1r6JlsfemQiLfklVksblt28onQIBL9+IUJTyPOcW3kUjJCmJVBL75hqTJ/rtjqCmsXLBZPCnAdJD060HwDyR703uo/11FVJCTX26Nvc6HPqvNyvmS+Awllaq8wftfTIudlJjrzxwYFukPj89sKiwqjvDezBzlLlPdbAEbxhgiGnDXXB8zHgtcMFRcrkc2901eY97Q8XNQG6GmwnKMiTztF8jETzzbatjFMBzw5CYIefHSPnpri5Tk9pmz8CMpG7S7ck2w4of4AhDQAgHqMIKFfj2eNterMVU8Id87sVJX/hLdcwNNh7+N3s2f4jB9O/0uzxD1Wdp/w32Ew+1hA7aRCQw==
//        [associated_data] => transaction
//        [nonce] => abWJebaUIXjV
//        )
//
//)
        $result = $this->request->param();
        if($result){
            $text = base64_decode($result['resource']['ciphertext']); //解密
            /* =========== 使用V3支付需要PHP7.2.6安装sodium扩展才能进行解密参数  ================ */
            $str = sodium_crypto_aead_aes256gcm_decrypt($text, $result['resource']['associated_data'], $result['resource']['nonce'], $this->apiV3Key);
            $res = json_decode($str, true);
            //如果成功返回了
            if($res['trade_state'] == 'SUCCESS'){
                Db::startTrans();
                try {
                    Db::name('service_order')->where('orderno',$res['out_trade_no'])->update([
                        'pay_state'=>1,
                        'transaction_id'=>$res['transaction_id'],
                        'pay_time'=>time(),
                        'status'=>1
                    ]);
                    $lid = Db::name('service_order')->where('orderno',$res['out_trade_no'])->value('lid');
                    if($lid){
                        Db::name('service_list')->where('id',$lid)->setInc('sales',1);
                    }
                    Db::commit();
                    return $this->json_result(200,'支付成功');
                }catch (DbException $e){
                    return $this->json_result(400,$e->getMessage());
                }
            }
        }
        return $this->json_result(400,'支付失败');
    }
}